home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
HPAVC
/
HPAVC CD-ROM.iso
/
ABUSESRC.ZIP
/
AbuseSrc
/
imlib
/
port
/
sgi
/
gen_drv.c
next >
Wrap
C/C++ Source or Header
|
1995-09-06
|
8KB
|
337 lines
#define NUM_CHANNELS 8
#define STDOUT_FD driver_out_fd
#define STDIN_FD driver_in_fd
#define DOUT_NAME "/tmp/sfxdrv.signal"
#define DIN_NAME "/tmp/sfxdrv.command"
enum { SFXCMD_QUIT,
SFXCMD_REGISTER,
SFXCMD_UNREGISTER,
SFXCMD_PLAY
};
class sfx_handle
{
public :
int shm_id;
void *shm_data_pointer;
sfx_handle *next;
long size;
int use_count;
} ;
int driver_out_fd,driver_in_fd;
sfx_handle *sfx_list=NULL;
#define TOTAL_SIGS 29
int sigs[TOTAL_SIGS]={SIGHUP,SIGINT,SIGQUIT,SIGILL,SIGTRAP,
SIGABRT,SIGIOT,SIGBUS,SIGFPE,SIGKILL,
SIGUSR1,SIGSEGV,SIGUSR2,SIGPIPE,SIGALRM,
SIGTERM,SIGCHLD,SIGCONT,SIGSTOP,
SIGTSTP,SIGTTIN,SIGTTOU,SIGIO,
SIGURG,SIGXCPU,SIGXFSZ,SIGVTALRM,SIGPROF,
SIGWINCH};
struct channel
{
unsigned char *data; // next data to be qued
long left; // how much is left to play?
unsigned char volume; // indexed into volume table
unsigned long add_time; // time at which the channel started playing
sfx_handle *snd; // pointer to actual sound, so delete can stop us if need be
} channels[NUM_CHANNELS];
#define uchar unsigned char
unsigned char buf[BUF_SIZE]; // mixing buffer
uchar volume_table[256*32]; // 32 volume settings
// add a new sound effect into the channel list, if no free channel
// oldest gets replaced with new sound
void play(sfx_handle *snd, unsigned char volume)
{
int i,free_channel=-1;
unsigned long oldest_channel=0,
oldest_channel_time=10000,
newest_channel_time=0;
for (i=0;i<NUM_CHANNELS;i++)
{
if (channels[i].data)
{
int my_time=channels[i].add_time;
if (my_time<oldest_channel_time)
{
oldest_channel=i;
oldest_channel_time=my_time;
}
if (my_time>newest_channel_time)
newest_channel_time=my_time;
} else free_channel=i;
}
if (free_channel==-1)
free_channel=oldest_channel;
channels[free_channel].snd=snd;
channels[free_channel].add_time=newest_channel_time+1;
channels[free_channel].data=(uchar *)snd->shm_data_pointer;
channels[free_channel].left=snd->size;
channels[free_channel].volume=volume*32/128;
}
int output_sounds() // return 0 if no sounds to ouput
{
unsigned char *s;
int i,j,bytes=0;
signed short sums[BUF_SIZE],run_size,*sp;
memset(sums,0,BUF_SIZE*sizeof(short));
for (j=0;j<NUM_CHANNELS;j++)
{
if (channels[j].data)
{
if (channels[j].left<BUF_SIZE) // hom many bytes will this channel run for?
run_size=channels[j].left;
else run_size=BUF_SIZE;
if (run_size>bytes) // how many bytes to output?
bytes=run_size;
// add the chanels together into a short
for (i=0,sp=sums;i<run_size;i++,sp++)
{
uchar cur_data=*(channels[j].data++);
short vol_data=volume_table[cur_data+channels[j].volume*256];
*sp+=vol_data-128;
}
if (channels[j].left<=BUF_SIZE)
channels[j].data=NULL;
else channels[j].left-=BUF_SIZE;
}
}
for (i=0,sp=sums,s=buf;i<BUF_SIZE;i++,s++,sp++)
{
#ifdef __linux__
if (*sp<-128) *s=0;
else if (*sp>127) *s=255;
else *s=(unsigned char)(*sp+128);
#else
if (*sp<-128) *s=((unsigned char)((signed char)-128));
else if (*sp>127) *s=((unsigned char)((signed char)127));
else *s=((unsigned char)((signed char)*sp));
#endif
}
output_samples(buf,BUF_SIZE);
return 1; // always say we have something, we will do blanks if nothing else
}
#ifdef __sgi
void clean_up(...)
#else
void clean_up(int why) // on exit unattach all shared memory links
#endif
{
while (sfx_list)
{
shmdt((char *)sfx_list->shm_data_pointer);
if (shmctl(sfx_list->shm_id,IPC_RMID,NULL)!=0)
printf("shmctl failed, why?\n");
sfx_handle *last=sfx_list;
sfx_list=sfx_list->next;
free(last);
}
sound_uninit();
unlink(DIN_NAME);
unlink(DOUT_NAME);
}
void die()
{ clean_up(0);
exit(0);
}
static int sound_fd_ready_to_read(int fd)
{
struct timeval tv={0,0};
fd_set kbd_set,ex_set;
FD_ZERO(&kbd_set);
FD_SET(fd,&kbd_set);
memcpy((void *)&ex_set,(void *)&kbd_set,sizeof(ex_set));
select(FD_SETSIZE,&kbd_set,NULL,&ex_set,&tv); // check for exception
if (FD_ISSET(fd,&ex_set))
die();
return (FD_ISSET(fd,&kbd_set));
}
void sound_watch()
{
while (1)
{
while (sound_fd_ready_to_read(STDIN_FD))
{
uchar cmd;
if (read(STDIN_FD,&cmd,1)!=1)
{ die(); }
switch (cmd)
{
case SFXCMD_REGISTER :
{
int shm_id;
long size;
uchar return_code;
if (read(STDIN_FD,&shm_id,sizeof(shm_id))!=sizeof(shm_id))
{ fprintf(stderr,"sndrv er1\n"); die(); }
if (read(STDIN_FD,&size,sizeof(size))!=sizeof(size))
{ fprintf(stderr,"sndrv er2\n"); die(); }
sfx_handle *sfx=new sfx_handle;
sfx->shm_id=shm_id;
sfx->shm_data_pointer=shmat(shm_id,NULL,0);
if (!sfx->shm_data_pointer)
{ fprintf(stderr,"Sound driver : unable to attach shared memory segment\n"); die(); }
sfx->size=size;
sfx->use_count=0;
sfx->next=sfx_list;
sfx_list=sfx;
cmd=1;
if (write(STDOUT_FD,&cmd,sizeof(cmd))!=sizeof(cmd))
{ fprintf(stderr,"sndrv er3\n"); die(); }
} break;
case SFXCMD_UNREGISTER :
{
int shm_id,i;
sfx_handle *f,*find=NULL,*last_find=NULL;
if (read(STDIN_FD,&shm_id,sizeof(shm_id))!=sizeof(shm_id))
{ die(); }
for (f=sfx_list;f && !find;f=f->next) // see if we can find the shm id in list
{
if (f->shm_id==shm_id)
find=f;
last_find=find; // svae last link so we can remove from the list
}
if (find)
{
// see if there are any sound channels playing this sound, if so stop them because
// memory is fixing to be deleted
for (int i=0;i<NUM_CHANNELS;i++)
{
if (channels[i].snd==find)
channels[i].data=NULL;
}
// now free the memory
shmdt((char *)find->shm_data_pointer); // detach and remove shm
if (last_find)
last_find->next=find->next; // unlink from sound list
else
sfx_list=sfx_list->next;
} else { fprintf(stderr,"Attempt to remove unknown sound effect\n"); die(); }
} break;
case SFXCMD_PLAY :
{
int shm_id,i,volume;
sfx_handle *f;
if (read(STDIN_FD,&shm_id,sizeof(shm_id))!=sizeof(shm_id))
die();
if (read(STDIN_FD,&volume,sizeof(volume))!=sizeof(volume))
die();
for (f=sfx_list;f && f->shm_id!=shm_id;f=f->next);
if (f)
play(f,volume);
else fprintf(stderr,"sound driver : bad id to play\n");
} break;
default : // die on unknown or DIE command
{ die(); }
}
}
output_sounds();
}
}
main()
{
uchar success=sound_init(); // initailize sound and send status to who ever ran us.
if (!success)
{
printf("-1");
return 0;
}
unlink(DIN_NAME);
unlink(DOUT_NAME);
// int old_mask=umask(S_IRWXU | S_IRWXG | S_IRWXO);
if (mkfifo(DIN_NAME,S_IRWXU | S_IRWXG | S_IRWXO))
{ perror("Sound driver : unable to make fifo in /tmp");
return 0;
}
chmod(DIN_NAME,S_IRWXU | S_IRWXG | S_IRWXO);
if (mkfifo(DOUT_NAME,S_IRWXU | S_IRWXG | S_IRWXO))
{ perror("Sound driver : unable to make fifo in /tmp");
return 0;
}
chmod(DOUT_NAME,S_IRWXU | S_IRWXG | S_IRWXO);
//umask(old_mask);
int chd=fork();
if (chd)
{
printf("%d\n",chd); // tell parent the sound driver's process number
return 0;
}
driver_out_fd=open(DOUT_NAME,O_RDWR);
if (driver_out_fd<0)
{ perror(DOUT_NAME);
exit(1);
}
driver_in_fd=open(DIN_NAME,O_RDWR);
if (driver_in_fd<0)
{ perror(DIN_NAME);
exit(1);
}
for (int i=0;i<TOTAL_SIGS;i++)
signal(sigs[i],clean_up);
sound_watch();
return 0;
}